Predictive Modelling – NMC Conditions

Nowcasting and short-term forecasts for notifiable conditions using EpiNow2

Overview

This section showcases nowcasting and short-term outbreak forecasting for key notifiable medical conditions (NMC) reported through the national surveillance system. The models use the EpiNow2 R package, which combines:

  • Nowcasting – adjusting for reporting delays
  • Estimation of \(R_t\) – the time-varying effective reproduction number
  • Short-term forecasting – projecting cases up to 3 weeks ahead
NoteConditions covered
NMC Category Conditions
Vaccine-preventable Fever-Rash (Measles + Rubella), Pertussis, Diphtheria, Tetanus, Hepatitis B, Haemophilus influenzae type B, Congenital rubella syndrome, Poliomyelitis / AFP, Yellow fever
Category 1 — Immediate notification (non-VPD) Cholera, Malaria, Covid-19, Enteric fever, Meningococcal disease, Listeriosis, Mpox
Category 2 — Routine notification Hepatitis A

Forecasts are only generated for conditions with ≥ 60 days of data.

TipLast forecast run

20 February 2026 23:54 — Horizon: 28 days — Conditions: Acute flaccid paralysis, Cholera, Congenital rubella syndrome, Covid-19, Diphtheria, Enteric fever (typhoid or paratyphoid fever), Haemophilus influenzae type B, Hepatitis A, Hepatitis B, Listeriosis, Malaria, Fever-Rash, Meningococcal disease, Mpox, Pertussis, Poliomyelitis, Tetanus, Yellow fever


Surveillance Epicurves

An epidemic curve of reported cases for each forecasted NMC condition, aggregated weekly at the national level.

Figure 1: Weekly reported cases for forecasted NMC conditions

EpiNow2 Forecasts

Each panel shows the median estimate (solid line), 50 % credible interval (dark ribbon) and 90 % credible interval (light ribbon), all smoothed with a 7-day rolling average to remove weekend reporting artefacts. The shaded forecast horizon extends 28 days (4 weeks) beyond the last data point.


Standard EpiNow2 Diagnostic Plots

The panels below show the native EpiNow2 diagnostic output for each condition. Each plot combines three key elements in a single view:

  1. Reported cases — observed data with nowcast / forecast and credible intervals
  2. Estimated infections — latent infection trajectory inferred by the model
  3. Effective reproduction number (\(R_t\)) — with threshold line at \(R_t = 1\)

These are produced directly by EpiNow2::plot() and provide a comprehensive snapshot of the epidemic state without any post-processing.


Animated Forecast Outlook

The rolling forecast shows how the predicted trajectory shifted each week as new data arrived. Each coloured line represents a forecast made on a different snapshot date; vertical markers show where each snapshot’s data ended.

This visualisation helps assess:

  • Forecast stability – are successive predictions consistent?
  • Outbreak acceleration – are newer forecasts trending higher?
  • Early warning – divergence between snapshots signals emerging outbreaks.
Figure 2: Rolling weekly EpiNow2 forecasts (animated)

Interpretation Guide

Table 1: How to read the forecast outputs

Element

What it means

Suggested action

Median line

Most likely trajectory based on current Rt

Monitor closely; compare to previous snapshots

50% CI (dark ribbon)

Central range – 1 in 2 chance the true value falls here

Normal operational uncertainty

90% CI (light ribbon)

Wide range – 9 in 10 chance the true value falls here

If real counts approach the upper bound → escalate

Forecast horizon (dashed red)

Where observed data ends and prediction begins

Predictions degrade further from this line

Rolling snapshots diverging upward

Successive forecasts are increasingly pessimistic

Possible outbreak acceleration → trigger response protocols

Rolling snapshots converging

Outbreak is stabilising or declining

Maintain surveillance; consider de-escalation


Effective Reproduction Number (\(R_t\))

The time-varying reproduction number \(R_t\) indicates how many secondary cases each infected person generates on average.

  • \(R_t > 1\) → epidemic is growing
  • \(R_t = 1\) → epidemic is stable
  • \(R_t < 1\) → epidemic is declining
Figure 3: Estimated Rt for vaccine-preventable conditions

Growth-Rate Summary Table

Table 2: Latest Rt and growth-rate summary per condition

Condition

Latest Rt

Lower 90%

Upper 90%

Assessment

Date

Acute flaccid paralysis

1.01

0.94

1.17

Growing

2026-03-19

Cholera

1.02

0.79

1.28

Growing

2026-03-19

Congenital rubella syndrome

0.84

0.59

1.04

Declining

2026-03-19

Covid-19

0.30

0.02

1.62

Declining

2026-03-19

Diphtheria

0.99

0.92

1.09

Stable / slow decline

2026-03-19

Enteric fever (typhoid or paratyphoid fever)

1.01

0.86

1.12

Growing

2026-03-19

Fever-Rash

0.76

0.42

1.25

Declining

2026-03-19

Haemophilus influenzae type B

1.00

0.94

1.06

Stable / slow decline

2026-03-19

Hepatitis A

0.98

0.79

1.12

Stable / slow decline

2026-03-19

Hepatitis B

0.96

0.57

1.56

Stable / slow decline

2026-03-19

Listeriosis

0.97

0.67

1.23

Stable / slow decline

2026-03-19

Malaria

0.43

0.19

1.00

Declining

2026-03-19

Meningococcal disease

0.99

0.91

1.06

Stable / slow decline

2026-03-19

Mpox

0.85

0.43

1.10

Declining

2026-03-19

Pertussis

0.94

0.76

1.09

Stable / slow decline

2026-03-19

Poliomyelitis

0.69

0.13

1.43

Declining

2026-03-19

Tetanus

0.93

0.61

1.27

Stable / slow decline

2026-03-19

Yellow fever

0.84

0.21

1.49

Declining

2026-03-19


Provincial Breakdown

Figure 4: Weekly cases by province for forecasted NMC conditions

Outbreak Capacity Indicator

A simple traffic-light display combining \(R_t\), recent case trends, and forecast trajectory.

Figure 5: Outbreak capacity indicator per condition

Updating Forecasts

ImportantStep-by-step instructions to refresh predictions

Forecasts are not computed live during dashboard rendering (they take ~5–15 min per condition). Instead, a batch script produces cached .rds files that the dashboard reads.

Prerequisites:

  1. R ≥ 4.3 with packages: EpiNow2, data.table, dplyr, lubridate, here, purrr
  2. CmdStan installed (EpiNow2 backend). Install via: cmdstanr::install_cmdstan()
  3. Aggregated surveillance data in data/processed/agg_national.rds (produced by R/prepare_dashboard_data.r)

1. Update the surveillance data

# From the project root
cd /Users/briday/Desktop/SAFETP/CLA/NMC_website/NMC_dashboard
Rscript R/prepare_dashboard_data.r

This reads the latest NMC master dataset and produces:

  • data/processed/agg_national.rds
  • data/processed/agg_province.rds
  • data/processed/agg_district.rds

2. Run the forecast batch

Rscript R/run_forecasts.r

This produces for each vaccine-preventable condition:

File Contents
forecasts_<condition>.rds Single-point EpiNow2 summary (Rt, cases, infections)
forecasts_obj_<condition>.rds Full EpiNow2 result object (for native plot() diagnostics)
forecasts_rolling_<condition>.rds Rolling snapshots for animated outlook
forecasts_meta.rds Run timestamp and parameters

3. Re-render the dashboard

quarto render by-forecasts/index.qmd
# Or render the full site:
quarto render

Configuration

Edit the constants at the top of R/run_forecasts.r to adjust:

Parameter Default Description
HORIZON 28 Days to forecast ahead (4 weeks)
LOOKBACK 360 Days of history for each model run
N_REWINDS 8 Number of rolling snapshots
REWIND_STEP 7 Days between snapshots

Adding a new condition

  1. Ensure the condition appears in agg_national.rds (via prepare_dashboard_data.r)
  2. Add disease parameters in R/epinow2_functions.rdisease_params() function
  3. Add the condition name to forecast_conditions() in the same file
  4. Re-run Rscript R/run_forecasts.r

Model Assumptions & Parameters

The table below shows the disease-specific parameters fed into each EpiNow2 forecast. These are defined in R/epinow2_functions.rdisease_params() and sourced from peer-reviewed epidemiological literature. The Reference column cites the primary source for each parameter set — check these when validating or updating assumptions.

Table 3: EpiNow2 model parameters by condition (with literature references)

Condition

Generation Time

Incubation Period

Rt Prior

Reporting Delay

What This Means

Reference

Fever-Rash

Gamma(shape~34, rate~2.9, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Fever-Rash to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Lessler et al. (2009) Lancet Infect Dis 9(5):291-300

Measles

Gamma(shape~34, rate~2.9, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Measles to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Lessler et al. (2009) Lancet Infect Dis 9(5):291-300

Rubella

Gamma(shape~27, rate~1.5, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Rubella to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Vink et al. (2014) Am J Epidemiol 180(9):865-875; Lessler et al. (2009)

Pertussis

Gamma(shape~13, rate~0.6, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Pertussis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Vink et al. (2014); Wearing & Rohani (2009) Emerg Infect Dis 15(8):1248

Diphtheria

Gamma(shape~7, rate~0.9, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Diphtheria to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Truelove et al. (2020) Emerg Infect Dis 26(10):2396; AAP Red Book

Tetanus

Gamma(shape~8, rate~0.6, max=--)

Gamma (see source)

Normal(mean=1.0, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Tetanus to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 1 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

WHO Tetanus Position Paper (2017); Roper et al. (2018) Lancet 391:1657

Hepatitis B

Gamma(shape~9, rate~0.1, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Hepatitis B to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Edmunds et al. (1993) Epidemiol Infect 110(3):569; Liang (2009) Hepatology 49(S5):S13

Haemophilus influenzae type B

Gamma(shape~4, rate~1.3, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Haemophilus influenzae type B to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Peltola (2000) Clin Microbiol Rev 13(2):302-317; AAP Red Book (2024)

Congenital rubella syndrome

Gamma(shape~27, rate~1.5, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Congenital rubella syndrome to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Vink et al. (2014); Lessler et al. (2009) – rubella parameters

Poliomyelitis

Gamma(shape~9, rate~0.6, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Poliomyelitis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Fine & Carneiro (1999) Am J Epidemiol 150(12):1332; Nathanson & Kew (2010) Am J Epidemiol 172(11):1213

Acute flaccid paralysis

Gamma(shape~9, rate~0.6, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Acute flaccid paralysis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Fine & Carneiro (1999) Am J Epidemiol 150(12):1332; Nathanson & Kew (2010) Am J Epidemiol 172(11):1213

Yellow fever

Gamma(shape~16, rate~1.3, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Yellow fever to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Johansson et al. (2010) Am J Trop Med Hyg 82(5):930; Monath & Vasconcelos (2015) J Clin Virol 64:160

Cholera

Gamma(shape~6, rate~1.2, max=--)

Gamma (see source)

Normal(mean=2.0, sd=1.0)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Cholera to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Azman et al. (2013) J Infect Dis 207(11):1698-1706

Malaria

Gamma(shape~14, rate~0.5, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Malaria to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Huber et al. (2016) Malar J 15:18; WHO World Malaria Report (2023)

Covid-19

Gamma(shape~6, rate~2.0, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Covid-19 to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Park et al. (2023) BMC Infect Dis 23:295; Wu et al. (2022) JAMA Netw Open 5(8):e2228008

Enteric fever (typhoid or paratyphoid fever)

Gamma(shape~12, rate~0.9, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Enteric fever (typhoid or paratyphoid fever) to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Pitzer et al. (2014) PLoS Negl Trop Dis 8(6):e2891; Crump et al. (2015) Clin Microbiol Rev 28(4):901

Meningococcal disease

Gamma(shape~8, rate~1.1, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Meningococcal disease to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Trotter et al. (2005) Emerg Infect Dis 11(4):563; Rosenstein et al. (2001) NEJM 344(18):1378

Listeriosis

Gamma(shape~4, rate~0.2, max=--)

Gamma (see source)

Normal(mean=1.2, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Listeriosis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 1 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Goulet et al. (2013) Clin Infect Dis 56(10):1411-1419

Mpox

Gamma(shape~8, rate~0.7, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Mpox to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Miura et al. (2022) Euro Surveill 27(44):2200806; Thornhill et al. (2022) NEJM 387(8):679

Hepatitis A

Gamma(shape~16, rate~0.7, max=--)

Gamma (see source)

Normal(mean=1.5, sd=0.5)

LogNormal(mean=3, sd=2, max=15)

On average, an infected person can spread Hepatitis A to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported.

Jacobsen & Wiersma (2010) Clin Liver Dis 14(4):591; Lemon et al. (2018) Lancet 391:1587

Generation time ≈ serial interval where direct measurement is unavailable. Incubation period = time from exposure to symptom onset. All distributions are Gamma. Reporting delay: default LogNormal(mean=3, sd=2, max=15) when empirical delay data is unavailable.

TipReading the parameters
Parameter What it controls Why it matters
Generation time Average time between successive infections in a chain (≈ serial interval) Determines how fast \(R_t\) changes translate into case-count changes
Incubation period Time from infection/exposure to symptom onset Affects the delay between infection dynamics and observed cases
\(R_t\) prior Starting assumption for reproduction number Weakly informative — the model quickly learns from data
Reporting delay Time from symptom onset to NMC notification Accounts for the surveillance lag between illness and official capture
What This Means Plain-language summary of all parameters for this condition Helps non-technical readers understand what the model assumes
Reference Primary literature source Used for validation — update if newer estimates become available
ImportantHow to adjust parameters

To update parameter values for a condition:

  1. Open R/epinow2_functions.r
  2. Find the condition in disease_params() (search for the condition name in lowercase)
  3. Change mean, sd, max values to match your preferred literature source
  4. Update the reference string to cite the new source
  5. Re-run: Rscript R/run_forecasts.r
  6. Re-render: quarto render by-forecasts/index.qmd

Example — changing measles generation time to use a new study:

"fever-rash" = , "measles" = list(
  generation_time   = EpiNow2::Gamma(mean = 11.0, sd = 2.5, max = 20),
  # ↑ changed from 11.7 to 11.0 based on New Study (2026)
  incubation_period = EpiNow2::Gamma(mean = 12.5, sd = 2.3, max = 21),
  rt_prior          = list(mean = 2, sd = 1),
  reference         = "New Study (2026) Journal Name DOI:..."
),

Methods & Technical Details

Model: EpiNow2 v1.8.0 – a Bayesian semi-mechanistic model that jointly estimates the effective reproduction number (\(R_t\)), infection incidence, and reporting patterns. The model is fitted using Hamiltonian Monte Carlo via CmdStan. A day-of-week effect is enabled (obs_opts(week_effect = TRUE)) to account for lower weekend reporting.

Display smoothing: All custom forecast plots apply a 7-day rolling average to both the observed surveillance series and the EpiNow2 median / credible-interval outputs. This removes residual day-of-week jaggedness and highlights the underlying epidemic trend.

Reporting delay: When empirical symptom→notification dates are available in the NMC data, the delay distribution is estimated via EpiNow2::estimate_delay() (capped at 15 days, max 100 observations). Otherwise a default LogNormal(mean=3, sd=2, max=15) prior is used.

Generation time & incubation period: Condition-specific Gamma distributions from published peer-reviewed literature. Key sources: Lessler et al. (2009) for measles/rubella; Vink et al. (2014) for serial intervals; Azman et al. (2013) for cholera; Park et al. (2023) for COVID-19 Omicron estimates. See the parameter table above for full citations. These are fixed inputs — not estimated from the data.

Priors: \(R_t\) priors are weakly informative: Normal(2, 1) for directly-transmitted pathogens, Normal(1.5, 0.5) for vector-borne / lower-Rt conditions. The model quickly learns from data.

Forecast horizon: 28 days (4 weeks) ahead from the last observation date.

History window: 360 days of surveillance data fed to each model run.

Completeness / Timeliness: The NMC is a passive surveillance system; under-reporting varies by condition and province. Forecasts represent reported cases, not true incidence.

Rolling forecast animation: Re-runs the model 8 times (weekly snapshots), each using data up to that snapshot date, to visualise how the forecast outlook evolved over time.